4.4 匹配范围
1、长度匹配
前面是单个元素的元字符,但都只能表示一个字符,以下是长度匹配
匹配模式 | 注释 |
---|---|
{n} | 只匹配n次,n是一个非负整数 |
{n,} | 至少匹配n次,n是一个非负整数 |
{n,m} | 至少匹配n次,最多匹配m次,m、n均是非负整数,m大于n |
* | 匹配前面的子表达式零次或多次,等价于{0,} |
+ | 匹配前面的子表达式1次以上,等价于{1,} |
? | 匹配前面的子表达式0次或1次,等价于{0,1} |
import re
text= "小张34-小明16-欧阳一大明45-小曾32"
t=re.compile( "\d{1,}" )
t1=re.compile( "\d+" )
p=t.findall(text)
p1=t1.findall(text)
print (p)
print (p1)
返回:
['34', '16', '45', '32']
['34', '16', '45', '32']
2、边界匹配
正则表达式中的边界匹配是指单词边界和首尾边界,边界匹配是匹配的位置
匹配模式 | 注释 |
---|---|
\b | 匹配空字符串,但只在单词开始或结尾的位置 |
\B | 匹配空字符串,但不能在单词开始或结尾 |
\A | 指定匹配必须出现在字符串的开头(忽略re.M选项) |
\Z | 指定匹配必须出现在字符串的结尾(忽略re.M选项) |
^ | 匹配字符串开始的位置,设置re.M后,支持多行 |
$ | 匹配字符串结尾的位置,设置re.M后,支持多行 |
3、分组匹配(常规分组)
分组,就是将正则表达式字符串中的被括号引用的部份为整体,匹配完成后,分组的内容可以被获取,并可以在之后用\number转义序列进行再次匹配,在python中,分组为普通分组与命名分组。
如果有多个分组,但只需获取某个分组的数据,使用findall()也可以,但如果匹配结果为re.match对象时,在获取数据时更方便,可能使用re.match对象的group()函数或者切片方式完成对分组数据的提取。
import re
text= "python20,pandas21,excel22"
t1=re.findall( "[A-Za-z]+\d+" ,text)
t2=re.findall( "([A-Za-z]+)(\d+)" ,text)
t3=re.findall( "(([A-Za-z]+)(\d+))" ,text)
print (t1)
print (t2)
print (t3)
print ("_____")
print (t2[0])
print (t3[0])
返回:
['python20', 'pandas21', 'excel22']
[('python', '20'), ('pandas', '21'), ('excel', '22')]
[('python20', 'python', '20'), ('pandas21', 'pandas', '21'), ('excel22', 'excel', '22')]
_____
('python', '20')
('python20', 'python', '20')
4、分组匹配(命名分组)
命名分组是python正则表达式中一种特殊的分组方式,它可以给分组改一个名称,从而在引用、获取分组数据时可以不用序号方式,而用名称来表示,命名分组很有用,因为允许你使用容易记住的名称,而不必记住数字。
分组命名格式为:在分组的左括号后面加?p<:名称>:,注意p字母是大写的,然后后面是正常的正则表达式字符串编写。
import re
text= "python20,pandas21,excel22"
t=re.finditer( "((?P<:name>:[A-Za-z]+)(?P<:score>:\d+))" ,text)
for m in t:
print (m.group( "name" ))
print (m.group( "score" ))
返回:
python
20
pandas
21
excel
22
5、分组匹配(命名分组)
分组的优点很多,除前面的re.match对象中获取分组数据的方法外,也可以在编写正则表达式字符串时再次引用,还可以使用sub()函数做替换引用。
import
re
text= "我们欢欢喜喜的来到公园,蹦蹦跳跳的,结果伤伤心心的走了"
t=re.finditer(r "([一-龥])\1([一-龥])\2" ,text)
print (t)
for m in t:
print (m.group())
返回:
<:callable_iterator object at 0x000001D0FEC57280>:
欢欢喜喜
蹦蹦跳跳
伤伤心心
6、分组在替换处理中的引用
除了正则表达式中引用分组之外,也可以在替换函数中使用,有以下三种引用方式:
(1)第一种引用的方式为\1、\2、\3、
(2)第二种引用的方式为\g<:1>:、\<:2>:、\<:3>:、
(2)第三种引用的方式为\g<:name1>:、\g<: name2>:、\ g<: name3>:、
import re
text= "89Bob100李小萌9王小花120Lucas85小曾"
t=re.findall( "(\d+)(\D+)" ,text)
s=re.sub( "(\d+)(\D+)",r"\2:\1、" ,text)
s1=re.sub( "(\d+)(\D+)" ,r "\g<:2>::\g<:1>:," ,text) #使用这种较好
print (t)
print (s)
print (s1)
返回:
[('89', 'Bob'), ('100', '李小萌'), ('9', '王小花'), ('120', 'Lucas'), ('85', '小曾')]
Bob:89、李小萌:100、王小花:9、Lucas:120、小曾:85、
Bob:89,李小萌:100,王小花:9,Lucas:120,小曾:85,
7、非捕获分组匹配
什么是非捕获分组匹配,就是具有分组匹配的功能,但并不对捕获到的分组内容进行存储。 在分组左括号加在?:即可,表示(?:……)匹配括号内的任何数据不会捕获储存,也不能被引用。
import re
text= "北京234上海32青岛56北京43上海97成都45"
t=re.findall( "(?:北京|上海)\d+" ,text)
t1=re.findall( "(北京|上海)\d+" ,text)
t2=re.findall( "北京|上海\d+" ,text)
print (t)
print (t1)
print (t2)
返回:
['北京234', '上海32', '北京43', '上海97']
['北京', '上海', '北京', '上海']
['北京', '上海32', '北京', '上海97']